﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SCEM.DTO;
using SCEM.DataLayer;
using SCEM.External;
using SCEM.ControleEstoque;

namespace SCEM.CompraProdutos
{
    /// <summary>
    /// Gerenciador de compra de produtos.
    /// </summary>
    public class GerenciadorCompraProdutos
    {
        /// <summary>
        /// Cria uma nova ordem de compra de produto e a salva no banco de dados se ela for autorizada pelo financeiro.
        /// </summary>
        /// <param name="dto">O DTO representando a nova ordem de compra de produto a ser gravada no banco de dados.</param>
        /// <returns>Um DTO representando a ordem de compra de produto gravada no banco, ou <code>null</code> caso o financeiro não autorize
        /// ou caso ocorra um erro.</returns>
        public OrdemCompraProdutoDTO CreateOrdemCompraProduto(OrdemCompraProdutoDTO dto)
        {
            // Validar o DTO enviado pelo usuário
            using (var context = new SCEMContainer())
            {
                // É possível converter o DTO em uma entidade corretamente (ie. existe a combinação fornecedor/produto)?
                if (dto == null)
                    return null;

                OrdemCompraProduto ordemTeste = dto.ConvertToEntity(context);
                if (ordemTeste == null || ordemTeste.Produto == null || ordemTeste.Fornecedor == null)
                    return null;

                // Existe realmente uma condição de venda cadastrada para esse par fornecedor/produto?
                CondicaoVendaDAO condicaoDAO = new CondicaoVendaDAO();
                CondicaoVendaDTO condicaoDTO = condicaoDAO.Get(dto.ProdutoId, dto.FornecedorId);
                if (condicaoDTO == null)
                    return null;

                // A quantidade escolhida pelo usuário é suficiente?
                if (ordemTeste.Quantidade < condicaoDTO.QuantidadeMinimaVenda)
                    return null;

                // O DTO aparenta ser válido, solicitar autorização para o financeiro
                dto.AutorizacaoFinanceiro = ExternalServiceRequestDispatcher.Instance.DispararNovaOrdemCompraProduto(dto.ProdutoId, dto.Quantidade * condicaoDTO.Preco);
                if (String.IsNullOrEmpty(dto.AutorizacaoFinanceiro)) // Não autorizado
                    return null;

                // Tudo OK, persistir a ordem de compra
                OrdemCompraProdutoDAO dao = new OrdemCompraProdutoDAO();
                OrdemCompraProdutoDTO dtoSave = (OrdemCompraProdutoDTO)dao.Save(dto);

                // Verificar se a ordem de compra foi persistida corretamente e, em caso negativo, cancelar a operação junto ao financeiro
                if (dtoSave == null)
                    ExternalServiceRequestDispatcher.Instance.CancelarOrdemCompraProduto(dto.AutorizacaoFinanceiro);

                return dtoSave;
                }            
        }

        /// <summary>
        /// Atualiza o status de uma ordem de compra de produto no banco de dados.
        /// Ordens de compra no estado CANCELADO ou FINALIZADO não podem ser alteradas.
        /// Além disso, ao se cancelar uma ordem de compra, é necessário disparar uma requisição para o financeiro para cancelar a transação.
        /// </summary>
        /// <param name="idOrdemCompraProduto">O id da ordem de compra de produto cujo status deseja-se atualizar.</param>
        /// <param name="novoStatus">O novo status dessa ordem de compra de produto.</param>
        /// <returns><code>true</code> em caso de sucesso, <code>false</code> caso contrário.</returns>
        public bool UpdateOrdemCompraProdutoStatus(string idOrdemCompraProduto, StatusOrdemCompra novoStatus)
        {
            // Buscar a ordem de compra de produto no banco
            IOrdemCompraProdutoDAO dao = new OrdemCompraProdutoDAO();
            OrdemCompraProdutoDTO dto = (OrdemCompraProdutoDTO)dao.Get(idOrdemCompraProduto);
            if (dto == null) // Ordem de compra inválida
                return false;

            // Caso a ordem de compra esteja no estado CANCELADO ou FINALIZADO, não é possível alterar nada
            if (dto.Status == StatusOrdemCompra.CANCELADO || dto.Status == StatusOrdemCompra.FINALIZADO)
                return (novoStatus == dto.Status);

            // Atualizar a ordem de compra
            dto.Status = novoStatus;
            if (dao.Update(dto) == null)
                return false;

            if (novoStatus == StatusOrdemCompra.CANCELADO)
            {
                // Em caso de cancelamento, informar o financeiro
                ExternalServiceRequestDispatcher.Instance.CancelarOrdemCompraProduto(dto.AutorizacaoFinanceiro);
            }
            else if (novoStatus == StatusOrdemCompra.FINALIZADO)
            {
                // Caso a ordem de compra seja marcada como finalizada, atualizar o estoque
                EstoqueControle gerenciadorEstoque = new EstoqueControle();
                gerenciadorEstoque.InsereProdutoEstoque(dto.ProdutoId, dto.Quantidade);
            }

            return true;
        }
        
    }
}
